home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume90 / unix / make / part02 / make.c
C/C++ Source or Header  |  1990-01-17  |  12KB  |  568 lines

  1. /*
  2.  *    Do the actual making for make
  3.  */
  4.  
  5. #include <stdio.h>
  6. #ifdef unix
  7. #include <sys/types.h>
  8. #include <sys/stat.h>
  9. #include <sys/errno.h>
  10. #endif
  11. #ifdef eon
  12. #include <sys/stat.h>
  13. #include <sys/err.h>
  14. #endif
  15. #ifdef os9
  16. #include <time.h>
  17. #include <os9.h>
  18. #include <modes.h>
  19. #include <direct.h>
  20. #include <errno.h>
  21. #endif
  22. #ifdef amiga
  23. #include <ctype.h>
  24. #include <errno.h>
  25. #include <libraries/dosextens.h>
  26. #include <exec/memory.h>
  27. #include <exec/io.h>
  28. #include <exec/ports.h>
  29. #include <functions.h>
  30. #undef TRUE            /*OIS*0.80*/
  31. #undef FALSE            /*OIS*0.80*/
  32. /*#define ACTION_SET_DATE     34L /*OIS*0.80*/
  33. #endif
  34. #include "h.h"
  35.  
  36.  
  37.  
  38. /*
  39.  *    Exec a shell that returns exit status correctly (/bin/esh).
  40.  *    The standard EON shell returns the process number of the last
  41.  *    async command, used by the debugger (ugg).
  42.  *    [exec on eon is like a fork+exec on unix]
  43.  */
  44. int
  45. dosh(string, shell)
  46.     char       *string;
  47.     char       *shell;
  48. {
  49.     int         number;
  50.  
  51. #ifdef amiga
  52.     char       *av[3], *s, *p;
  53.     int         i;
  54.  
  55.     fflush(stdout); /*OIS*0.80*/
  56.     if ((p = s = malloc((unsigned) strlen(string) + 1)) == NULL)
  57.     fatal("No memory for command '%s'", string);
  58.     strcpy(p, string);                  /* make a copy of the string */
  59.     i = 0;
  60.     av[0] = gettok(&p);                 /* get first argument */
  61.     av[1] = p;                /* get rest of command line */
  62.     av[2] = NULL;
  63.     if (fexecv(av[0], av) == -1)
  64.     fatal("couldn't execute command '%s', error return %02x\n",
  65.           av[0], errno);
  66.     number = wait();
  67.     free(s);
  68.     return number;
  69. #endif
  70.  
  71. #ifdef unix
  72.     return system(string);
  73. #endif
  74. #ifdef eon
  75.     return ((number = execl(shell, shell, "-c", string, 0)) == -1) ?
  76.     -1 :            /* couldn't start the shell */
  77.     wait(number);           /* return its exit status */
  78. #endif
  79. #ifdef os9
  80.     int         status, pid;
  81.  
  82.     strcat(string, "\n");
  83.     if ((number = os9fork(shell, strlen(string), string, 0, 0, 0)) == -1)
  84.     return -1;        /* Couldn't start a shell */
  85.     do {
  86.     if ((pid = wait(&status)) == -1)
  87.         return -1;        /* child already died!?!? */
  88.     } while (pid != number);
  89.  
  90.     return status;
  91. #endif
  92. }
  93.  
  94.  
  95. /*
  96.  *    Do commands to make a target
  97.  */
  98. void
  99. docmds1(np, lp)
  100.     struct name    *np;
  101.     struct line    *lp;
  102. {
  103.     bool        ssilent;
  104.     bool        signore;
  105.     int         estat;
  106.     register char  *q;
  107.     register char  *p;
  108.     char       *shell;
  109.     register struct cmd *cp;
  110. #ifdef amiga
  111.     long SetSignal();
  112. #endif
  113.  
  114. #ifndef amiga
  115.     if (*(shell = getmacro("SHELL")) == '\0')
  116. #ifdef eon
  117.     shell = ":bin/esh";
  118. #endif
  119. #ifdef unix
  120.     shell = "/bin/sh";
  121. #endif
  122. #ifdef os9
  123.     shell = "shell";
  124. #endif
  125. #else /* for amiga */
  126.     shell = NULL;
  127. #endif
  128.  
  129.     for (cp = lp->l_cmd; cp; cp = cp->c_next) {
  130.     strcpy(str1, cp->c_cmd);
  131.     expand(str1);
  132.     q = str1;
  133.     ssilent = silent;
  134.     signore = ignore;
  135.     while ((*q == '@') || (*q == '-')) {
  136.         if (*q == '@')      /* Specific silent  */
  137.         ssilent = TRUE;
  138.         else        /* Specific ignore  */
  139.         signore = TRUE;
  140.         q++;        /* Not part of the command  */
  141.     }
  142.  
  143.     if (!domake)
  144.         ssilent = 0;
  145.  
  146.     if (!ssilent)
  147.         fputs("    ", stdout);
  148.  
  149.     for (p = q; *p; p++) {
  150.         if (*p == '\n' && p[1] != '\0') {
  151.         *p = ' ';
  152.         if (!ssilent)
  153.             fputs("\\\n", stdout);
  154.         } else if (!ssilent)
  155.         putchar(*p);
  156.     }
  157.     if (!ssilent)
  158.         putchar('\n');
  159.  
  160.     if (domake) {           /* Get the shell to execute it  */
  161.         if ((estat = dosh(q, shell)) != 0) {
  162.         if (estat == -1)
  163.             fatal("Couldn't execute %s", shell);
  164.         else {
  165.             printf("%s: Error code %d", myname, estat);
  166.             if (signore)
  167.             fputs(" (Ignored)\n", stdout);
  168.             else {
  169.             putchar('\n');
  170.             if (!(np->n_flag & N_PREC))
  171.                 if (unlink(np->n_name) == 0)
  172.                 printf("%s: '%s' removed.\n", myname, np->n_name);
  173.             exit(estat);
  174.             }
  175.         }
  176.         }
  177. #ifdef amiga
  178.         if ((SetSignal(0L, SIGBREAKF_CTRL_D) & SIGBREAKF_CTRL_D) != 0) {
  179.         fatal("Abort due to ^D");   /*OIS*0.80*/
  180.         }
  181. #endif
  182.     }
  183.     }
  184. }
  185.  
  186.  
  187. docmds(np)
  188.     struct name    *np;
  189. {
  190.     register struct line *lp;
  191.  
  192.  
  193.     for (lp = np->n_line; lp; lp = lp->l_next)
  194.     docmds1(np, lp);
  195. }
  196.  
  197.  
  198. #ifdef os9
  199. /*
  200.  *    Some stuffing around to get the modified time of a file
  201.  *    in an os9 file system
  202.  */
  203. getmdate(fd, tbp)
  204.     struct sgtbuf  *tbp;
  205. {
  206.     struct registers regs;
  207.     static struct fildes fdbuf;
  208.  
  209.  
  210.     regs.rg_a = fd;
  211.     regs.rg_b = SS_FD;
  212.     regs.rg_x = &fdbuf;
  213.     regs.rg_y = sizeof(fdbuf);
  214.  
  215.     if (_os9(I_GETSTT, ®s) == -1) {
  216.     errno = regs.rg_b & 0xff;
  217.     return -1;
  218.     }
  219.     if (tbp) {
  220.     _strass(tbp, fdbuf.fd_date, sizeof(fdbuf.fd_date));
  221.     tbp->t_second = 0;    /* Files are only acurate to mins */
  222.     }
  223.     return 0;
  224. }
  225.  
  226.  
  227. /*
  228.  *    Kludge routine to return an aproximation of how many
  229.  *    seconds since 1980.  Dates will be in order, but will not
  230.  *    be lineer
  231.  */
  232. time_t
  233. cnvtime(tbp)
  234.     struct sgtbuf  *tbp;
  235. {
  236.     long        acc;
  237.  
  238.  
  239.     acc = tbp->t_year - 80;    /* Baseyear is 1980 */
  240.     acc = acc * 12 + tbp->t_month;
  241.     acc = acc * 31 + tbp->t_day;
  242.     acc = acc * 24 + tbp->t_hour;
  243.     acc = acc * 60 + tbp->t_minute;
  244.     acc = acc * 60 + tbp->t_second;
  245.  
  246.     return acc;
  247. }
  248.  
  249.  
  250. /*
  251.  *    Get the current time in the internal format
  252.  */
  253. time(tp)
  254.     time_t       *tp;
  255. {
  256.     struct sgtbuf   tbuf;
  257.  
  258.  
  259.     if (getime(&tbuf) < 0)
  260.     return -1;
  261.  
  262.     if (tp)
  263.     *tp = cnvtime(&tbuf);
  264.  
  265.     return 0;
  266. }
  267. #endif
  268.  
  269.  
  270. /*
  271.  *    Get the modification time of a file.  If the first
  272.  *    doesn't exist, it's modtime is set to 0.
  273.  */
  274. void
  275. modtime(np)
  276.     struct name    *np;
  277. {
  278. #ifdef unix
  279.     struct stat     info;
  280.     int         fd;
  281.  
  282.  
  283.     if (stat(np->n_name, &info) < 0) {
  284.     if (errno != ENOENT)
  285.         fatal("Can't open %s; error %d", np->n_name, errno);
  286.  
  287.     np->n_time = 0L;
  288.     } else
  289.     np->n_time = info.st_mtime;
  290. #endif
  291. #ifdef eon
  292.     struct stat     info;
  293.     int         fd;
  294.  
  295.  
  296.     if ((fd = open(np->n_name, 0)) < 0) {
  297.     if (errno != ER_NOTF)
  298.         fatal("Can't open %s; error %02x", np->n_name, errno);
  299.  
  300.     np->n_time = 0L;
  301.     } else if (getstat(fd, &info) < 0)
  302.     fatal("Can't getstat %s; error %02x", np->n_name, errno);
  303.     else
  304.     np->n_time = info.st_mod;
  305.  
  306.     close(fd);
  307. #endif
  308. #ifdef os9
  309.     struct sgtbuf   info;
  310.     int         fd;
  311.  
  312.  
  313.     if ((fd = open(np->n_name, 0)) < 0) {
  314.     if (errno != E_PNNF)
  315.         fatal("Can't open %s; error %02x", np->n_name, errno);
  316.  
  317.     np->n_time = 0L;
  318.     } else if (getmdate(fd, &info) < 0)
  319.     fatal("Can't getstat %s; error %02x", np->n_name, errno);
  320.     else
  321.     np->n_time = cnvtime(&info);
  322.  
  323.     close(fd);
  324. #endif
  325. #ifdef amiga
  326.     struct FileInfoBlock *fib;
  327.     struct FileLock *myLock;
  328.     long ioErr;
  329.  
  330.     fib = (struct FileInfoBlock *) malloc((unsigned) sizeof(struct FileInfoBlock));
  331.     if ((myLock = Lock(np->n_name, ACCESS_READ)) == NULL) {
  332.     if ((ioErr = IoErr()) != ERROR_OBJECT_NOT_FOUND)
  333.         fatal("Can't Lock '%s'; error %3ld", np->n_name, ioErr);
  334.     np->n_time = 0L;
  335.     } else if (!Examine(myLock, fib)) {
  336.     UnLock(myLock);
  337.     fatal("Can't Examine '%s'; error %3ld", np->n_name, IoErr());
  338.     } else {
  339.     np->n_time = fib->fib_Date.ds_Tick/TICKS_PER_SECOND +
  340.          60*fib->fib_Date.ds_Minute + 86400*fib->fib_Date.ds_Days;
  341.     UnLock(myLock);
  342.     }
  343.     free((char *) fib);
  344. #endif
  345.  
  346. }
  347.  
  348. #ifdef amiga
  349. char *
  350. nametail(name)
  351. register char *name;
  352. {
  353.     register char *tail;
  354.  
  355.     if ((tail = index(name, ':')) == NULL)      /* strip device name */
  356.     tail = name;
  357.     if ((name = rindex(tail, '/')) == NULL)     /* strip directories */
  358.     name = tail;
  359.  
  360.     return name;
  361. }
  362. #endif
  363.  
  364.  
  365. /*
  366.  *    Update the mod time of a file to now.
  367.  */
  368. void
  369. touch(np)
  370.     struct name    *np;
  371. {
  372.     char        c;
  373.     int         fd;
  374.  
  375.  
  376.     if (!domake || !silent)
  377.     printf("    touch(%s)\n", np->n_name);
  378.  
  379.     if (domake) {
  380. #ifdef unix
  381.     long        a[2];
  382.  
  383.     a[0] = a[1] = time(0);
  384.     if (utime(np->n_name, &a[0]) < 0)
  385.         printf("%s: '%s' not touched - non-existant\n",
  386.            myname, np->n_name);
  387. #endif
  388. #ifdef eon
  389.     if ((fd = open(np->n_name, 0)) < 0)
  390.         printf("%s: '%s' not touched - non-existant\n",
  391.            myname, np->n_name);
  392.     else {
  393.         uread(fd, &c, 1, 0);
  394.         uwrite(fd, &c, 1);
  395.     }
  396.     close(fd);
  397. #endif
  398. #ifdef os9
  399.     /*
  400.      * Strange that something almost as totally useless as this is easy
  401.      * to do in os9!
  402.      */
  403.     if ((fd = open(np->n_name, S_IWRITE)) < 0)
  404.         printf("%s: '%s' not touched - non-existant\n",
  405.            myname, np->n_name);
  406.     close(fd);
  407. #endif
  408. #ifdef amiga
  409.     struct MsgPort *task;
  410.     ULONG dateStamp[3];
  411.     struct FileLock *lock, *plock;
  412.     UBYTE *bcplstring;
  413.  
  414.     if(!(bcplstring = (UBYTE *)AllocMem(64L, MEMF_PUBLIC)))
  415.         fatal("Can't get 64 bytes for bcplstring");
  416.     if(!(task=(struct MsgPort *)DeviceProc(np->n_name))) {
  417.         printf("%s: can't get MsgPort for '%s'\n", myname, np->n_name);
  418.         goto abort;
  419.     }
  420.     if(!(lock = Lock(np->n_name, SHARED_LOCK))) {
  421.         printf("%s: '%s' not touched - non-existant\n",
  422.             myname, np->n_name);
  423.         goto abort;
  424.     }
  425.     plock = ParentDir(lock);
  426.     UnLock(lock);
  427.  
  428.     /* Strip pathnames first */
  429.     strcpy((bcplstring + 1), nametail(np->n_name));
  430.     *bcplstring = strlen(bcplstring + 1);
  431.  
  432.     dos_packet(task, ACTION_SET_DATE, NULL, plock, (ULONG)bcplstring >> 2,
  433.         (ULONG) DateStamp(dateStamp), 0L, 0L, 0L);
  434.  
  435.     UnLock(plock);
  436. abort:
  437.     FreeMem((void *) bcplstring, 64L);
  438. #endif
  439.     }
  440. }
  441.  
  442. /*
  443.  * Recursive routine to make a target.
  444.  */
  445. int
  446. make(np, level)
  447.     struct name    *np;
  448.     int         level;
  449. {
  450.     register struct depend *dp;
  451.     register struct line *lp;
  452.     register struct depend *qdp;
  453.     time_t        dtime = 1, time();
  454.     bool        didsomething = 0;
  455.     char *        basename  = (char *) 0;
  456.     char *        inputname = (char *) 0;
  457.  
  458.  
  459.     if (np->n_flag & N_DONE)
  460.     return 0;
  461.  
  462.     if (!np->n_time)
  463.     modtime(np);            /* Gets modtime of this file  */
  464.  
  465.     if (rules) {
  466.     for (lp = np->n_line; lp; lp = lp->l_next)
  467.         if (lp->l_cmd)
  468.         break;
  469.     if (!lp)
  470.         dyndep(np, &basename, &inputname);
  471.     }
  472.     if (!(np->n_flag & N_TARG) && np->n_time == 0L)
  473.     fatal("Don't know how to make %s", np->n_name);
  474.  
  475.     for (qdp = (struct depend *) 0, lp = np->n_line; lp; lp = lp->l_next) {
  476.     for (dp = lp->l_dep; dp; dp = dp->d_next) {
  477.         make(dp->d_name, level + 1);
  478.         if (np->n_time < dp->d_name->n_time)
  479.         qdp = newdep(dp->d_name, qdp);
  480.         dtime = max(dtime, dp->d_name->n_time);
  481.     }
  482.     if (!quest && (np->n_flag & N_DOUBLE) && (np->n_time < dtime)) {
  483.         make1(np, lp, qdp, basename, inputname); /* free()'s qdp */
  484.         dtime = 1;
  485.         qdp = (struct depend *) 0;
  486.         didsomething++;
  487.     }
  488.     }
  489.  
  490.     np->n_flag |= N_DONE;
  491.  
  492.     if (quest) {
  493.     long        t;
  494.  
  495.     t = np->n_time;
  496.     time(&np->n_time);
  497.     if (basename)
  498.         free(basename);
  499.  
  500.     return t < dtime;
  501.     } else if (np->n_time < dtime && !(np->n_flag & N_DOUBLE)) {
  502.     make1(np, (struct line *)0, qdp, basename, inputname); /* free()'s qdp */
  503.     time(&np->n_time);
  504.     } else if (level == 0 && !didsomething)
  505.     printf("%s: '%s' is up to date\n", myname, np->n_name);
  506.  
  507.     if (basename)
  508.     free(basename);
  509.  
  510.     return 0;
  511. }
  512.  
  513.  
  514. make1(np, lp, qdp, basename, inputname)
  515.     register struct depend *qdp;
  516.     struct line    *lp;
  517.     struct name    *np;
  518.     char       *basename;
  519.     char       *inputname;
  520. {
  521.     register struct depend *dp;
  522.  
  523.  
  524.     if (dotouch)
  525.     touch(np);
  526.     else {
  527.     strcpy(str1, "");
  528.     if (!basename)
  529.         basename = str1;
  530.     setmacro("*", basename);        /* $* = file */
  531.     if (!inputname)
  532.         inputname = str1;
  533.     setmacro("<", inputname);       /* $< = path/file.c or file.c */
  534.     for (dp = qdp; dp; dp = qdp) {
  535.         if (strlen(str1))
  536.         strcat(str1, " ");
  537.         strcat(str1, dp->d_name->n_name);
  538.         qdp = dp->d_next;
  539.         free(dp);
  540.     }
  541.     setmacro("?", str1);            /* $? = file.c file1.h file2.h */
  542.     setmacro("@", np->n_name);      /* $@ = file.o */
  543.     if (lp)                 /* lp set if doing a :: rule */
  544.         docmds1(np, lp);
  545.     else
  546.         docmds(np);
  547.     }
  548. }
  549. #ifdef amiga
  550. /*
  551.  * Replace the Aztec-provided time function with one which returns something
  552.  * easy to find and compare, namely the number of seconds since the Amiga's
  553.  * reference date.  This is the same thing returned by modtime() above.
  554.  */
  555. time_t
  556. time(v)
  557.     time_t *v;
  558. {
  559.     long t[3];
  560.  
  561.     DateStamp(t);
  562.     t[0] = t[2]/TICKS_PER_SECOND + 60*t[1] + 86400*t[0];
  563.     if (v)
  564.     *v = t[0];
  565.     return t[0];
  566. }
  567. #endif
  568.